﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using DomainExample.DomainModel.PersonModel;

namespace DomainExample.Repository
{
    public interface IPersonRepository : IRepository<Person, PersonId>
    {
        IEnumerable<Person> GetForSearch(PersonSearch personSearch);
    }

    public sealed class PersonRepository : BaseRepository, IPersonRepository
    {
        internal PersonRepository(IDataProvider dataProvider) 
            : base(dataProvider) { }

        public Person GetById(PersonId personId)
        {
            const string query = "SELECT Id, FirstName, LastName FROM Person WHERE Id = @id";

            var command = NewCommand(query);
            AddParameter(command, "Id", personId.Value);
            
            var results = GetEntitiesFromDatabase<Person>(command);
            return results.SingleOrDefault();
        }

        public IEnumerable<Person> GetForSearch(PersonSearch personSearch)
        {
            throw new NotImplementedException();
        }

        public Person Persist(Person person)
        {
            return person.Id.Value == 0 ? Add(person) : Edit(person);
        }

        public void Remove(PersonId personId)
        {
            const string query = "DELETE FROM Person WHERE Id = @id";

            var command = NewCommand(query);
            AddParameter(command, "Id", personId.Value);
            ExecuteNonQuery(command);
        }

        protected override object MapRowToEntity(IDataReader reader)
        {
            var person = Person.NewPerson(PersonId.NewPersonId(reader.GetInt32(reader.GetOrdinal("Id"))));
            person.FirstName = reader.GetString(reader.GetOrdinal("FirstName"));
            person.LastName = reader.GetString(reader.GetOrdinal("LastName"));
            return person;
        }

        private Person Add(Person person)
        {
            const string query = "INSERT INTO Person (FirstName, LastName) VALUES (@firstName, @lastName)";
            Int32 newPersonid;

            var command = NewCommand(query);
            AddParameter(command, "firstName", person.FirstName);
            AddParameter(command, "lastName", person.LastName);

            ExecuteInsert(command, out newPersonid);
            person.Id = PersonId.NewPersonId(newPersonid);
            return person;
        }

        private Person Edit(Person person)
        {
            const string query = "UPDATE Person SET FirstName = @firstName, LastName = @lastName WHERE Id = @id";

            var command = NewCommand(query);
            AddParameter(command, "firstName", person.FirstName);
            AddParameter(command, "lastName", person.LastName);
            AddParameter(command, "id", person.Id.Value);
            
            ExecuteNonQuery(command);

            return person;
        }
    }
}
